package cn.edu.nwpu.warehousemanagement.service.impl;

import cn.edu.nwpu.warehousemanagement.constantEnum.FreightStatus;
import cn.edu.nwpu.warehousemanagement.constantEnum.OperationType;
import cn.edu.nwpu.warehousemanagement.constantEnum.ShelfStatus;
import cn.edu.nwpu.warehousemanagement.dao.*;
import cn.edu.nwpu.warehousemanagement.pojo.*;
import cn.edu.nwpu.warehousemanagement.pojo.dto.InBoundDTO;
import cn.edu.nwpu.warehousemanagement.service.InBoundService;
import cn.edu.nwpu.warehousemanagement.pojo.Result;
import cn.edu.nwpu.warehousemanagement.util.IncrementUtil;
import cn.edu.nwpu.warehousemanagement.util.ThreadLocalUtil;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class InBoundServiceImpl implements InBoundService {

    // 批量处理大小
    private static final int BATCH_SIZE = 1000;

    private final ShelfRepository shelfRepository;
    private final ProductRepository productRepository;
    private final FreightRepository freightRepository;
    private final InventoryRecordRepository inventoryRecordRepository;
    private final InventoryConfigRepository inventoryConfigRepository;

    @Override
    @Transactional
    public Result<?> InBound(List<InBoundDTO> inBoundDTOs) {
        if (inBoundDTOs == null || inBoundDTOs.isEmpty()) {
            return Result.error("入库数据不能为空");
        }

        // 1. 数据预处理和校验
        ValidationResult validation = validateInBoundDTOs(inBoundDTOs);
        if (!validation.errors.isEmpty()) {
            return Result.error("校验失败: " + String.join("; ", validation.errors));
        }

        // 2. 批量保存货品
        List<Freight> freights = createFreights(validation);
        saveFreightsInBatches(freights);

        // 3. 创建入库记录
        List<InventoryRecord> records = createInventoryRecords(validation.batchMap, freights);
        inventoryRecordRepository.saveAll(records);

        // 4. 更新库存数量
        updateProductQuantities(validation.productQuantityMap);

        return Result.success("入库成功");
    }

    // 校验逻辑
    private ValidationResult validateInBoundDTOs(List<InBoundDTO> dtos) {
        ValidationResult result = new ValidationResult();
        Map<Long, Shelf> shelfCache = new ConcurrentHashMap<>();
        Map<Long, Product> productCache = new ConcurrentHashMap<>();
        Set<Long> shelfIds = new HashSet<>();
        Set<Long> productIds = new HashSet<>();
        String batchId = genBatchId();

        //收集所有ID
        for (int i = 0; i < dtos.size(); i++) {
            InBoundDTO dto = dtos.get(i);
            try {
                //设置batchId和boxId
                dto.setBatchId(batchId);
                String boxId = batchId + "-" + String.format("%03d", i + 1);
                dto.setBoxId(boxId);

                Long shelfId = Long.parseLong(dto.getShelfId());
                Long productId = Long.parseLong(dto.getItemId());

                shelfIds.add(shelfId);
                productIds.add(productId);
                result.batchMap.computeIfAbsent(dto.getBatchId(), k -> new ArrayList<>()).add(dto);
            } catch (NumberFormatException e) {
                result.errors.add("ID格式错误: " + dto);
            }
        }

//        // 收集所有ID
//        for (InBoundDTO dto : dtos) {
//            try {
//                Long shelfId = Long.parseLong(dto.getShelfId());
//                Long productId = Long.parseLong(dto.getItemId());
//
//                shelfIds.add(shelfId);
//                productIds.add(productId);
//                result.batchMap.computeIfAbsent(dto.getBatchId(), k -> new ArrayList<>()).add(dto);
//            } catch (NumberFormatException e) {
//                result.errors.add("ID格式错误: " + dto);
//            }
//        }

        // 批量查询货架和商品
        shelfCache.putAll(shelfRepository.findByIdInAndDeletedFalse(shelfIds)
                .stream()
                .collect(Collectors.toMap(Shelf::getId, Function.identity())));

        productCache.putAll(productRepository.findByIdInAndDeletedFalse(productIds)
                .stream()
                .collect(Collectors.toMap(Product::getId, Function.identity())));

        // 详细校验
        for (int i = 0; i < dtos.size(); i++) {
            InBoundDTO dto = dtos.get(i);
            try {
                Long shelfId = Long.parseLong(dto.getShelfId());
                Long productId = Long.parseLong(dto.getItemId());

                Shelf shelf = shelfCache.get(shelfId);
                if (shelf == null) {
                    result.errors.add("记录#" + (i+1) + ": 货架不存在");
                    continue;
                }
                if (shelf.getShelfStatus() != ShelfStatus.Normal) {
                    result.errors.add("记录#" + (i+1) + ": 货架状态异常: " + shelf.getShelfStatus());
                }

                Product product = productCache.get(productId);
                if (product == null) {
                    result.errors.add("记录#" + (i+1) + ": 商品不存在");
                }

                // 记录库存变更
                if (shelf != null && product != null) {
                    result.productQuantityMap.merge(product, 1L, Long::sum);
                }
            } catch (NumberFormatException e) {
                result.errors.add("记录#" + (i+1) + ": ID转换错误");
            }
        }

        return result;
    }

    // 创建货品对象
    private List<Freight> createFreights(ValidationResult validation) {
        List<Freight> freights = new ArrayList<>();
        LocalDateTime now = LocalDateTime.now();

        validation.batchMap.forEach((batchId, dtos) -> {
            for (InBoundDTO dto : dtos) {
                try {
                    Freight freight = new Freight();
                    freight.setShelf(new Shelf(Long.parseLong(dto.getShelfId())));
                    freight.setProduct(new Product(Long.parseLong(dto.getItemId())));
                    freight.setBoxId(dto.getBoxId());
                    freight.setInboundTime(now);
                    freight.setStatus(FreightStatus.IN_STOCK);
                    freight.setDeleted(false);
                    freights.add(freight);
                } catch (NumberFormatException ignored) {
                    // 已在前置校验中处理
                }
            }
        });
        return freights;
    }

    // 批量保存货品
    private void saveFreightsInBatches(List<Freight> freights) {
        int total = freights.size();
        for (int i = 0; i < total; i += BATCH_SIZE) {
            int end = Math.min(i + BATCH_SIZE, total);
            List<Freight> batch = freights.subList(i, end);
            freightRepository.saveAll(batch);
            freightRepository.flush(); // 防止内存溢出
        }
    }

    // 创建入库记录
    private List<InventoryRecord> createInventoryRecords(
            Map<String, List<InBoundDTO>> batchMap,
            List<Freight> freights) {

        List<InventoryRecord> records = new ArrayList<>();
        LocalDateTime now = LocalDateTime.now();
        Map<String, List<Freight>> freightByBatch = freights.stream()
                .collect(Collectors.groupingBy(f -> {
                    // 通过DTO查找对应的batchId
                    return batchMap.entrySet().stream()
                            .filter(e -> e.getValue().stream()
                                    .anyMatch(dto -> dto.getBoxId().equals(f.getBoxId())))
                            .findFirst()
                            .map(Map.Entry::getKey)
                            .orElse("");
                }));

        freightByBatch.forEach((batchId, batchFreights) -> {
            InventoryRecord record = new InventoryRecord(
                    OperationType.INBOUND,
                    ThreadLocalUtil.getLoginUserId(),
                    now,
                    batchId
            );
            record.setFreights(batchFreights);
            record.setDeleted(false);
            records.add(record);
        });

        return records;
    }

    // 更新商品库存数量
    private void updateProductQuantities(Map<Product, Long> quantityMap) {
        quantityMap.forEach((product, delta) -> {
            try {
                productRepository.updateQuantity(product.getId(), delta);
            } catch (Exception e) {
                log.error("更新库存失败: productId={}, delta={}", product.getId(), delta, e);
            }
        });
    }

    // 校验结果容器
    private static class ValidationResult {
        final List<String> errors = new ArrayList<>();
        final Map<String, List<InBoundDTO>> batchMap = new HashMap<>();
        final Map<Product, Long> productQuantityMap = new ConcurrentHashMap<>();
    }


    private static String genBatchId() {
//        // 统一使用第一条数据的日期生成批次号
//        LocalDate inboundDate = inBoundDTOS.get(0).getInboundDate();
        //使用当前时间生成BatchId
        LocalDate inboundDate = LocalDate.now();
        String dateStr = inboundDate.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        //从单例模式中获取一个静态的值
        long existingCount = IncrementUtil.getIncrement();
        String batchId = dateStr + "-" + String.format("%02d", existingCount + 1);
        return batchId;
    }

}